/////*system header*//////
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/////*user header*/////
#include "../include/test.h"
#include "../include/process.h"
#include "../include/thread.h"
#include "../include/socket_unix.h"
#include "../include/posix_ipc.h"

/////*global variables */////
// Command mapping table
Command commands[] = {
    /* Process functions */
    {"fork",      process_fork,             "System call fork()",                     "./<command> fork [count]",                 NULL},
    {"exec",      process_exec,             "System call exec()",                     "./<command> exec [program]",               NULL},
    {"redirect",  shell_redirection,        "Shell input/output redirection",         "./<command> redirect [input] [output]",    NULL},
    {"mtrace",    process_mtrace,           "Memory allocation tracing",              "./<command> mtrace",                       NULL},
    {"valgrind",  process_valgrind,         "Memory detection tool",                  "./<command> valgrind",                     NULL},
    {"calloc",    process_calloc,           "Dynamic memory allocation (calloc)",     "./<command> calloc [size]",                NULL},
    {"realloc",   process_realloc,          "Dynamic memory reallocation (realloc)",  "./<command> realloc [old_size] [new_size]",NULL},
    {"fileshare", process_fork_file_share,  "Parent-child process file sharing",      "./<command> fileshare [filename]",         NULL},
    {"signal",    process_signal_sync,      "Process signal synchronization",         "./<command> signal",                       NULL},
    {"atexit",    process_atexit,           "Process exit handling (atexit)",         "./<command> atexit",                       NULL},
    {"onexit",    process_onexit,           "Process exit handling (onexit)",         "./<command> onexit",                       NULL},
    {"stdbuff",   process_stdio_buff,       "Standard IO buffering mode",             "./<command> stdbuff [mode]",               NULL},
    {"wait",      process_wait,             "Process waiting (wait)",                 "./<command> wait",                         NULL},
    {"waitpid",   process_waitpid,          "Process waiting (waitpid)",              "./<command> waitpid [options]",            NULL},

    /* Thread functions */
    {"pthread",   thread_pthread_func,      "Thread creation and basic operations",   "./<command> pthread [count]",              NULL},
    {"mutex",     thread_mutex_lock_unlock, "Thread mutex lock operations",           "./<command> mutex",                        NULL},
    {"mutex-init",thread_mutex_init,        "Thread mutex initialization",            "./<command> mutex-init",                   NULL},
    {"cont",      thread_producter_consumer,"Producer-consumer model",                "./<command> cont [buffer_size]",           NULL},

    /* Socket functions */
    {"str-ser",   socket_stream_server,     "UNIX domain stream socket server",       "./<command> str-ser [socket_path]",        NULL},
    {"str-cli",   socket_stream_client,     "UNIX domain stream socket client",       "./<command> str-cli [socket_path]",        NULL},
    {"dgr-ser",   socket_dgram_server,      "UNIX domain datagram socket server",     "./<command> dgr-ser [socket_path]",        NULL},
    {"dgr-cli",   socket_dgram_client,      "UNIX domain datagram socket client",     "./<command> dgr-cli [socket_path]",        NULL},

    /* IPC functions */
    {"pipe",      ipc_pipe,                 "POSIX pipe communication",               "./<command> pipe",                         NULL},
    {"popen",     ipc_popen,                "Pipe stream operations",                 "./<command> popen",                        NULL},
    {"fifo-r",    ipc_fifo_read,            "Named pipe (FIFO) reading",              "./<command> fifo-r [fifo_path]",           NULL},
    {"fifo-w",    ipc_fifo_write,           "Named pipe (FIFO) writing",              "./<command> fifo-w [fifo_path]",           NULL},
    {"mq-r",      ipc_mqueue_recive,        "POSIX message queue receiving",          "./<command> mq-r [mq_name]",               NULL},
    {"mq-w",      ipc_mqueue_send,          "POSIX message queue sending",            "./<command> mq-w [mq_name]",               NULL},
    {"shm-r",     ipc_shm_read,             "Shared memory reading",                  "./<command> shm-r [shm_name]",             NULL},
    {"shm-w",     ipc_shm_write,            "Shared memory writing",                  "./<command> shm-w [shm_name]",             NULL},

    /* End marker */
    {NULL,        NULL,                     NULL,                                     NULL,                                       NULL}
};

/////*functions */////
int main(int argc,char *argv[])
{
    // No arguments, show general help
    if (argc < 2) 
    {
        print_general_help(argv[0]);
        return 1;
    }

    // Find command
    Command *cmd = find_command(argv[1]);
    if (!cmd) 
    {
        printf("Error: Unknown command '%s'\n", argv[1]);
        print_general_help(argv[0]);
        return 1;
    }

    // Extract subcommand arguments (starting from argv[2])
    int sub_argc = argc - 1;
    char **sub_argv = &argv[1];

    // Parameter validation
    if (cmd->validator && cmd->validator(sub_argc) != 0) 
    {
        printf("Error: Invalid parameter format\n");
        print_command_help(cmd->name,argv[0]);
        return 1;
    }

    // Execute command handler function
    cmd->handler(sub_argc, sub_argv);

    return 0;
}

// Find command handler function
Command* find_command(const char *name) 
{
    for (int i = 0; commands[i].name != NULL; i++) 
    {
        if (strcmp(commands[i].name, name) == 0) 
        {
            return &commands[i];
        }
    }
    return NULL;
}

// Get program name
const char* get_progname(void) {
    static char *progname = NULL;
    if (!progname) {
        progname = strrchr(__FILE__, '/');
        progname = progname ? progname + 1 : __FILE__;
    }
    return progname;
}

// Display general help information
void print_general_help(char *str) {
    printf("Usage: %s [command] [arguments...]\n", str);
    printf("Available commands:\n");
    for (int i = 0; commands[i].name != NULL; i++) {
        printf("  %-10s - %s\n", commands[i].name, \
            commands[i].description);
    }
    //printf("\nUse '%s help [command]' for detailed information about a specific command\n", 
    //    argv[0]);
}

// Display specific command help information
void print_command_help(const char *cmd_name,char *str) {
    Command *cmd = find_command(cmd_name);
    if (cmd) {
        printf("Command: %s - %s\n", cmd->name, cmd->description);
        if (cmd->usage[0]) {
            printf("Usage: %s %s %s\n", str, \
            cmd->name, cmd->usage);
        }
    } else {
        printf("Error: Unknown command '%s'\n", cmd_name);
        print_general_help(str);
    }
}

// Help command handler function
void print_help(int argc, char *argv[]) {
    if (argc > 1) {
        print_command_help(argv[1],argv[0]);
    } else {
        print_general_help(argv[0]);
    }
}
